namespace MoreLinq;

using System;
using System.Collections.Generic;
using System.Linq;

static partial class MoreEnumerable
{
    /// <summary>
    /// Determines whether the beginning of the first sequence is
    /// equivalent to the second sequence, using the default equality
    /// comparer.
    /// </summary>
    /// <typeparam name="T">Type of elements.</typeparam>
    /// <param name="first">The sequence to check.</param>
    /// <param name="second">The sequence to compare to.</param>
    /// <returns>
    /// <c>true</c> if <paramref name="first" /> begins with elements
    /// equivalent to <paramref name="second" />.
    /// </returns>
    /// <remarks>
    /// This is the <see cref="IEnumerable{T}" /> equivalent of
    /// <see cref="string.StartsWith(string)" /> and it calls
    /// <see cref="IEqualityComparer{T}.Equals(T,T)" /> using
    /// <see cref="EqualityComparer{T}.Default"/> on pairs of elements at
    /// the same index.
    /// </remarks>

    public static bool StartsWith<T>(this IEnumerable<T> first, IEnumerable<T> second)
    {
            return StartsWith(first, second, null);
        }

    /// <summary>
    /// Determines whether the beginning of the first sequence is
    /// equivalent to the second sequence, using the specified element
    /// equality comparer.
    /// </summary>
    /// <typeparam name="T">Type of elements.</typeparam>
    /// <param name="first">The sequence to check.</param>
    /// <param name="second">The sequence to compare to.</param>
    /// <param name="comparer">Equality comparer to use.</param>
    /// <returns>
    /// <c>true</c> if <paramref name="first" /> begins with elements
    /// equivalent to <paramref name="second" />.
    /// </returns>
    /// <remarks>
    /// This is the <see cref="IEnumerable{T}" /> equivalent of
    /// <see cref="string.StartsWith(string)" /> and
    /// it calls <see cref="IEqualityComparer{T}.Equals(T,T)" /> on pairs
    /// of elements at the same index.
    /// </remarks>

    public static bool StartsWith<T>(this IEnumerable<T> first, IEnumerable<T> second, IEqualityComparer<T>? comparer)
    {
            if (first == null) throw new ArgumentNullException(nameof(first));
            if (second == null) throw new ArgumentNullException(nameof(second));

            if (first.TryAsCollectionLike() is { Count: var firstCount } &&
                second.TryAsCollectionLike() is { Count: var secondCount } &&
                secondCount > firstCount)
            {
                return false;
            }

            comparer ??= EqualityComparer<T>.Default;

            using var firstIter = first.GetEnumerator();
            return second.All(item => firstIter.MoveNext() && comparer.Equals(firstIter.Current, item));
        }
}
